#ifndef ZIPFILE_H
#define ZIPFILE_H

class ZipEntry;
class UnzipStream;

class ZipFile
{
	public:
		ZipFile();
		~ZipFile();

		bool8 open(const String& filename);
		void close();

		ZipEntry* getZipEntries() const;

		int32 getFileLen() const;
		int32 read(void* Buf, int32 Amt);
		int32 seek(int32 Ofs, int32 Whence);
		int32 tell();

	protected:
		bool8 determineFileLen();

	protected:
		pCStream file;
		int32 flen;
		ZipEntry* entry;
};

class ZipEntry
{
	friend ZipFile;

	public:
		~ZipEntry();

		// returns 0 for directories and encrypted files
		//
		UnzipStream* getUnzipStream(ZipFile* ZF);

		bool8 isDirectory();
		bool8 isEncrypted();
		bool8 isFilenameValid();

		ZipEntry* getNext();

	protected:
		ZipEntry(class ZFHEntry&);
		
	private:
		ZipEntry() { /* not used */ }

	public:
		enum Constants
		{
			STORED			= 0,
			DEFLATED		= 8
		};

		uint16 flags;
		uint16 method;					// compression method
		uint32 filecrc32;
		uint32 compressedSize;
		uint32 uncompressedSize;
		uint32 headerOfs;
//		uint16 filenameLen;
//		uint8* filename;				// ALWAYS has '/' as path separator
		String filename;

	protected:
		ZipEntry* next;
};

class UnzipStream
{
	public:
		virtual ~UnzipStream();

		// returns -1 when eof, <-1 if error, 0 no data yet, >0 amtRead
		//
		virtual int32 read(uint8* buf, int32 bufSize) = 0;

	protected:
		UnzipStream() { /* unused */ }
		UnzipStream(ZipFile* , ZipEntry*);

	protected:
		ZipFile* zf;
		ZipEntry* ze;
		int32 remain;
		uint32 crc;
};

inline ZipEntry*
ZipFile::getZipEntries() const
{
	return entry;
}

inline int32
ZipFile::getFileLen() const
{
	return flen;
}
inline
ZipEntry::~ZipEntry()
{
//	delete [] filename;
}

inline ZipEntry*
ZipEntry::getNext()
{
	return next;
}

inline bool8
ZipEntry::isEncrypted()
{
	return (bool8)((flags & 1) != 0);
}

inline bool8
ZipEntry::isFilenameValid()
{
	return (bool8)(filename[0] != '-');		// zip'ed from stdin
}

inline
UnzipStream::~UnzipStream()
{
}

#endif
